#include <stdio.h>
#include <stdlib.h>
#include <time.h>

/*	matrix_sum3D.cpp
*	This program is part of the °Simple-Benchs° Benchmark
*	The complexity of this program is O(n³) where n is the Matrix's size
*
*	
*	To run the program:	./program (Matrix's size) (Max element)
*/

/* Array initialization. Complexity O(n³) where n is the matrix's size*/
void initArray(int ***vet, int rows, int columns, int planes, int max_num) {
  int count, count2, count3;
  for (count = 0; count < planes; count++) {
    vet[count] = (int**) malloc(rows * sizeof(int*));
    for (count2 = 0; count2 < rows; count2++) {
      vet[count][count2] = (int*) malloc(columns * sizeof(int));
      for (count3 = 0; count3 < columns; count3++) {
       vet[count][count2][count3] = rand() % max_num;
      }
    }
  }
}

/* Program standart output. Display a Matrix.  Complexity O(n³) where n is the matrix's size */
void printArray(int ***vet, int rows, int columns, int planes) {
  int count, count2, count3;
  printf("\n\t============= MATRIX ============\n");
  for (count = 0; count < planes; count++) {
    for (count2=0; count2 < rows; count2++) {
      for (count3=0; count3 < columns; count3++) {
        printf("\t%d", vet[count][count2][count3]);
      }
    printf("\n");
    }
  printf("\n");
  }
}


/*	Perform the Matrix sum. Complexity O(n²) defined by the nested loops starting the line 48, 
where n is the number of rows/columns in the input three-dimensional tensor */
int*** sum(int ***matA, int ***matB, int rows, int columns, int planes) {
    int count, count2, count3;
    int ***result = (int***) malloc(planes * sizeof(int**));
    for (count=0; count < planes; count++) {
    	result[count] = (int**) malloc(rows * sizeof(int*));
        for(count2=0; count2 < rows; count2++){
          result[count][count2] = (int*) malloc(columns * sizeof(int));
          for(count3=0; count3 < columns; count3++){
        	   result[count][count2][count3] = matA[count][count2][count3] + matB[count][count2][count3];
          }
        }
    }
    return result;
}

/*	Initial check to verify whether the amount of arguments is correct or not.  Complexity O(1)	*/
short Initial_check(int inputs){
    if (inputs != 3 && inputs != 5) {
        fprintf(stderr,"Wrong number of argments. Syntax: ./program num_rows num_columns num_planes max_element\n");
        return 1;
    }
    return 0;
}

/*	Auxiliar function to free all blocks in heap. Complexity O(n²) where n is the size of the three-dimensional tensor */
void free_all(int ***matA, int ***matB, int ***matC, int rows, int planes){
  int count2,count;
  for (count = 0; count < planes; count++){
    for (count2 = 0; count2 < rows; count2++){
      free(matA[count][count2]);
      free(matB[count][count2]);
      free(matC[count][count2]);
    }
    free(matA[count]);
    free(matB[count]);
    free(matC[count]);
  }
  free(matA);
  free(matB);
  free(matC);
}

int main(int argc, char** argv) {

	/* Checking arguments */
  if (Initial_check(argc)) return 1;

  /* Retrieve problem size. */
  int rows = atoi(argv[1]);
  int columns = atoi(argv[2]);
  int planes;
  int max_num;
  if (argv[3] == NULL){
    max_num = columns;
    columns = rows;
    planes = rows;
  }else{
    planes = atoi(argv[3]);
    max_num = atoi(argv[4]);
  }
  
  /* Seed initialization. */
  srand((unsigned)time(NULL));

  /* Variable declaration/allocation/initialization. */
  int ***matA = (int***) malloc(planes * sizeof(int**));
  int ***matB = (int***) malloc(planes * sizeof(int**));  
  int ***result;
  initArray(matA, rows, columns, planes, max_num);
  initArray(matB, rows, columns, planes, max_num);
  
  /*	Computing the sum */
  result = sum(matA, matB, rows, columns, planes);

  /* Display the result*/  	
  printArray(matA, rows, columns, planes);
  printArray(matB, rows, columns, planes);
  printArray(result, rows, columns, planes);

  /* Be clean. */
  free_all(matA,matB,result,rows,planes);

  return 0;
}
